/*
   A collection of miscellaneous utilities that operate on the templated 
   tree.hh class.

   (At the moment only a printing utility.
   Linda Buisman, linda.buisman@studentmail.newcastle.edu.au)

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#ifndef tree_util_hh_
#define tree_util_hh_

#include <iostream>
#include "tree_sort.hh"

namespace kptree {

template<class T>
void print_tree_bracketed(const tree<T>& t, std::ostream& str=std::cout);

template<class T>
void print_subtree_bracketed(const tree<T>& t, typename tree<T>::iterator iRoot, 
                             std::ostream& str=std::cout);



// Iterate over all roots (the head) and print each one on a new line
// by calling printSingleRoot.

template<class T>
void print_tree_bracketed(const tree<T>& t, std::ostream& str) 
   {
   int headCount = t.number_of_siblings(t.begin());
   int headNum = 0;
   for(typename tree<T>::sibling_iterator iRoots = t.begin(); iRoots != t.end(); iRoots++) {
      print_subtree_bracketed(t,iRoots,str);
      if (headNum <= headCount - 1) {
         str << std::endl;
         }
      }
   }


// Print everything under this root in a flat, bracketed structure.

template<class T>
void print_subtree_bracketed(const tree<T>& t, typename tree<T>::iterator iRoot, std::ostream& str) 
   {
   if(t.empty()) return;
   if (t.number_of_children(iRoot) == 0) {
      str << *iRoot; 
      }
   else {
      // parent
      str << *iRoot;
      str << "(";
      // child1, ..., childn
      int siblingCount = t.number_of_siblings(t.begin(iRoot));
      int siblingNum;
      typename tree<T>::sibling_iterator iChildren;
      for (iChildren = t.begin(iRoot), siblingNum = 0; iChildren != t.end(iRoot); ++iChildren, ++siblingNum) {
         // recursively print child
         print_subtree_bracketed(t,iChildren,str);
         // comma after every child except the last one
         if (siblingNum != siblingCount - 1 ) {
            str << ", ";
            }
         }
      str << ")";
      }
   }

};

/*
* $Id: tree_util.hh 80333 2008-07-27 15:05:39Z lexus $
*
* Copyright 2008 by Sunbay Software Crimea Ltd.
* Prospekt Kirova 29/1 office 432, 95000 Simferopol, Ukraine
* All rights reserved
*
*/
template<class T>
class TreeDiff
{
	typename tree_sort<T>::sibling_iterator SetParentData(tree_sort<T>& _tree, tree_node_<T>* node_tree);
	void GetDiff(const tree_sort<T>& treeOld, const tree_sort<T>& treeNew,
				typename tree_sort<T>::sibling_iterator iterOld, typename tree_sort<T>::sibling_iterator iterNew,
				tree_sort<T>& treeDelete, tree_sort<T>& treeAdd);
public:
	void GetDiff(const tree_sort<T>& treeOld, const tree_sort<T>& treeNew, tree_sort<T>& treeDelete, tree_sort<T>& treeAdd);
};

template<class T>
typename tree_sort<T>::sibling_iterator TreeDiff<T>::SetParentData(tree_sort<T>& _tree, tree_node_<T>* node_tree)
{
	if(node_tree)
	{
		if(node_tree->parent)
			return _tree.append_child(SetParentData(_tree, node_tree->parent), node_tree->data);
		else
			return _tree.insert(SetParentData(_tree, node_tree->parent), node_tree->data);
	}
	return _tree.end();
}

template<class T>
void TreeDiff<T>::GetDiff(const tree_sort<T>& treeOld, const tree_sort<T>& treeNew, tree_sort<T>& treeDelete, tree_sort<T>& treeAdd)
{
	GetDiff(treeOld, treeNew, treeOld.begin(), treeNew.begin(), treeDelete, treeAdd);
}

template<class T>
void TreeDiff<T>::GetDiff(const tree_sort<T>& treeOld, const tree_sort<T>& treeNew,
						  typename tree_sort<T>::sibling_iterator iterOld, typename tree_sort<T>::sibling_iterator iterNew,
						  tree_sort<T>& treeDelete, tree_sort<T>& treeAdd)
{
	tree_sort<T>::sibling_iterator itOld = treeOld.begin_sibling(iterOld);
	tree_sort<T>::sibling_iterator itNew = treeNew.begin_sibling(iterNew);
	for (;itNew != treeNew.end_sibling(iterNew) && itOld != treeOld.end_sibling(iterOld);)
	{
		if(*itOld < *itNew)
		{
			if(itOld.parent_)
				treeDelete.append_child(SetParentData(treeDelete, itOld.parent_), *itOld);
			else
				treeDelete.insert(SetParentData(treeDelete, itOld.parent_), *itOld);
			itOld++;
		}
		else if(*itNew < *itOld)
		{
			tree_sort<T>::sibling_iterator itTemp = SetParentData(treeAdd, itNew.parent_);
			if(itOld.parent_)
				treeAdd.append_children(treeAdd.append_child(itTemp, *itNew), itNew.node->first_child, itNew.node->last_child);
			else if(itTemp != treeAdd.end())
				treeAdd.insert_subtree(itTemp.begin(), itNew);
			else
				treeAdd.insert_subtree(itTemp, itNew);
			itNew++;
		}
		else if(*itNew == *itOld)
		{
			GetDiff(treeOld, treeNew, itOld.begin(), itNew.begin(), treeDelete, treeAdd);
			itOld++;
			itNew++;
		}
	}
	if(itNew == treeNew.end_sibling(iterNew))
	{
		tree_sort<T>::sibling_iterator it; 
		if(itOld != treeOld.end_sibling(iterOld))
			it = SetParentData(treeDelete, itOld.parent_);
		for(;itOld != treeOld.end_sibling(iterOld); itOld++)
		{
			if(it != treeDelete.end())
				treeDelete.append_child(it, *itOld);
			else
				treeDelete.insert(it, *itOld);
		}
	}
	else if(itOld == treeOld.end_sibling(iterOld))
	{
		tree_sort<T>::sibling_iterator it; 
		if(itNew != treeNew.end_sibling(iterNew))
			it = SetParentData(treeAdd, itNew.parent_);
		for(;itNew != treeNew.end_sibling(iterNew); itNew++)
		{
			if(it != treeAdd.end())
				treeAdd.insert_subtree(it.begin(), itNew);
			else
				treeAdd.insert_subtree(it, itNew);
		}
	}
}

#endif
